package org.luo.lan.server.config;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.luo.lan.common.Constant;
import org.luo.lan.common.config.AbstractConfig;
import org.luo.lan.common.util.Md5PasswordEncoder;
import org.luo.lan.common.util.Pair;
import org.luo.lan.common.util.StringUtils;
import org.luo.lan.server.enums.ProxyTypeEnum;
import org.luo.lan.server.factory.BridgeChannelFactory;

import java.util.*;

/**
 * @Auther: luobiao
 * @Date: 2020/9/19 09:15
 * @Description:
 */
@Slf4j
public class ServerConfig extends AbstractConfig<ServerInfo> {
    private static ServerConfig instance = null;
    private Map<String, String> clientHashMap = new HashMap<>();


    private ServerConfig() {
        this.configFileName = Constant.SERVER_CONFIG_FILE_NAME;
        this.configInfoClass = ServerInfo.class;
        ServerInfo config = init();
        if (config != null && config.getClientMap().size() > 0) {
            updateClientHash();
        }
    }

    private void updateClientHash(){
        clientHashMap.clear();
        config.getClientMap().forEach((k, v) -> {
            clientHashMap.put(k, Md5PasswordEncoder.encode(JSONObject.toJSONString(v)));
        });
    }

    /**
     * 在配置被修改时剔除掉那些被修改的client
     */
    @Override
    protected void doUpdate() {
        Map<String, ServerInfo.Client> clientMap = config.getClientMap();
        List<String> clearClient = new ArrayList();
        if (clientMap != null) {
            Set<String> oldClientList = clientHashMap.keySet();
            Set<String> newClientList = clientMap.keySet();
            if (newClientList != null && newClientList.size() > 0) {
                oldClientList.stream().forEach(k -> {
                    if (newClientList.contains(k)) {
                        if (clientMap.get(k) != null) {
                            String newHash = Md5PasswordEncoder.encode(JSONObject.toJSONString(clientMap.get(k)));
                            if (newHash != null && !newHash.equals(clientHashMap.get(k))) {
                                //说明这个client配置被修改了
                                clearClient.add(k);
                            }
                        }
                    } else {
                        clearClient.add(k);
                    }
                });
            }
            updateClientHash();
        }
        if (!clearClient.isEmpty()) {
            clearClient.stream().forEach(k -> {
                log.debug("客户端{}配置被修改了！",k);
                BridgeChannelFactory.INSTANCE.closeBridgeChannel(k);
            });
        }
    }

    @Override
    protected Pair<Boolean, String> checkConfig(ServerInfo serverInfo) {
        Pair<Boolean, String> pair = new Pair(true, "配置校验通过！");
        Map<Object, String> proxyMap = new HashMap<>();
        Map<String, ServerInfo.Client> clientMap = serverInfo.getClientMap();
        if (clientMap != null) {
            for (String clientKey : clientMap.keySet()) {
                for (ProxyTypeEnum proxyTypeEnum : ProxyTypeEnum.values()) {
                    ServerInfo.Client client = clientMap.get(clientKey);
                    if (client != null) {
                        for (Pair<String, String> k : proxyTypeEnum.getProxyKeys(client)) {
                            if (proxyMap.containsKey(k.getKey())) {
                                return new Pair(false, String.format("客户端 %s 中的 %s %s 与已存在的配置有冲突！", clientKey, proxyTypeEnum.getDesc(), k.getKey()));
                            }
                            proxyMap.put(k.getKey(), k.getValue());
                        }
                    }

                }
            }
        }
        return pair;
    }

    public static ServerConfig getInstance() {
        if (instance == null) {
            synchronized (ServerConfig.class) {
                if (instance == null)
                    instance = new ServerConfig();
            }
        }
        return instance;
    }

    public synchronized int getDomainProxyPort() {
        return config.getServer().getDomain_proxy_port();
    }

    public synchronized int getBridgePort() {
        return config.getServer().getBridge_port();
    }

    public synchronized String getSslFileName() {
        return Constant.USER_DIR + this.config.getServer().getSsl_file_name();
    }

    public synchronized String getSslPwd() {
        return config.getServer().getSsl_pwd();
    }


    public synchronized ServerInfo.Client getClient(String clientKey) {
        ServerInfo.Client client = config.getClientMap().get(clientKey);
       /* ServerInfo.Client existClient = null;
        if (StringUtils.isBlank(clientKey)) {
            return existClient;
        }
        synchronized(this){
            existClient = clientMapCache.get(clientKey);
            if (existClient == null) {
                List<ServerInfo.Client> clientList= this.config.getClientList();
                existClient=clientList.stream().filter(c-> StringUtils.isNotBlank(c.getKey())&&c.getKey().equals(clientKey)).findFirst().orElse(null);
                if (existClient != null) {
                    clientMapCache.put(clientKey, existClient);
                }
            }
        }*/
        return client;
    }

}
